package system

import (
	"server/common/dto/response"
	"server/enumeration"
	"server/model"
	"server/repo"
	serviceRequest "server/service/dto/request"
	serviceResponse "server/service/dto/response"
	"server/utils"
)

type MenuService struct {
	Repository *repo.Repository[model.Menu]
}

func NewMenuServiceApp(repository *repo.Repository[model.Menu]) *MenuService {
	return &MenuService{
		Repository: repository,
	}
}

func menuNotFoundHandler() *response.ServiceError {
	return response.WrapError(response.MenuNotFoundCode, response.GetStatusCode(response.MenuNotFoundCode).Message)
}

func menuExistsHandler() *response.ServiceError {
	return response.WrapError(response.MenuExistsCode, response.GetStatusCode(response.MenuExistsCode).Message)
}

func (ms *MenuService) CreateMenuInfoService(requestdata *serviceRequest.CreateMenuRequest) *response.ServiceError {
	condition := map[string]interface{}{
		"name": requestdata.Name,
		"code": requestdata.Code,
	}
	var menu model.Menu
	if err := utils.ModelToStruct(&menu, requestdata); err != nil {
		return err
	}
	return ms.Repository.GenericCreateWithData(condition, &menu, "OR", menuExistsHandler)
}

func (ms *MenuService) DeleteMenuInfoService(id string) (bool, *response.ServiceError) {
	return ms.Repository.GenericLogicDeleteById(id, "OR", menuNotFoundHandler)
}

func (ms *MenuService) ModifyMenuInfoService(requestData *serviceRequest.ModifyMenuRequest) (bool, *response.ServiceError) {
	return ms.Repository.GenericModifyByCondition(requestData.ID, &requestData, menuNotFoundHandler)
}

func (ms *MenuService) GetMenuInfoService(id string) (*serviceResponse.MenuResponse, *response.ServiceError) {
	menu, err := ms.Repository.GenericQueryDetailById(id, nil)
	if err != nil {
		return nil, err
	}
	return ms.buildMenuResponse(menu)
}

func (ms *MenuService) GetMenuListService(requestData *serviceRequest.MenuQueryRequest) (*[]serviceResponse.MenuResponse, *response.ServiceError) {
	condition, err := utils.StructToMapWithoutZero(&requestData)
	if err != nil {
		return nil, err
	}
	menus, err := ms.Repository.GenericQueryListByCondition("", "", condition)
	if err != nil {
		return nil, err
	}
	return ms.buildMenuListResponse(menus)
}

func (ms *MenuService) GetMenuPageService(requestData *serviceRequest.MenuQueryRequest) (*response.PageResponse[serviceResponse.MenuResponse], *response.ServiceError) {
	condition, err := utils.StructToMapWithoutZero(requestData)
	if err != nil {
		return nil, err
	}
	pageData, menus, err := ms.Repository.GenericQueryPageByCondition(requestData.Page, requestData.Size, "", "", condition)
	if err != nil {
		return nil, err
	}
	menuListResponse, err := ms.buildMenuListResponse(menus)
	if err != nil {
		return nil, err
	}
	var pageResponse response.PageResponse[serviceResponse.MenuResponse]
	pageResponse.Page = pageData.Page
	pageResponse.Size = pageData.Size
	pageResponse.Total = pageData.Total
	pageResponse.List = *menuListResponse
	return &pageResponse, nil
}

func (ms *MenuService) buildMenuResponse(menu model.Menu) (*serviceResponse.MenuResponse, *response.ServiceError) {
	var menuResponse serviceResponse.MenuResponse
	if err := utils.ModelToStruct(&menuResponse, &menu); err != nil {
		return nil, err
	}
	menuResponse.StatusName = enumeration.CommonStatus(menu.Status).StatusString()
	menuResponse.LevelName = enumeration.MenuLevel(menu.Level).MenuLevelString()
	return &menuResponse, nil
}

func (ms *MenuService) buildMenuListResponse(menus []model.Menu) (*[]serviceResponse.MenuResponse, *response.ServiceError) {
	var menuListResponse []serviceResponse.MenuResponse
	for _, menu := range menus {
		menuResponse, err := ms.buildMenuResponse(menu)
		if err != nil {
			return nil, err
		}
		menuListResponse = append(menuListResponse, *menuResponse)
	}
	return &menuListResponse, nil
}
